{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "start_time": "2022-03-25T14:01:58.272Z"
    },
    "code_folding": [
     19,
     48
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "start\n",
      "使用`开始可以进行，鼠标左键截选要识别的文字部分，按m重新选择，按ESC结束选择,再次按ESC退出此模块，鼠标右键也可\n",
      "请使用鼠标左键开始选择，可以多次选择。按“c”后可以移动图纸接着选择\n",
      "可以重新按tab选择图片，此时设置钩子\n",
      "请使用鼠标左键开始选择，可以多次选择。按“c”后可以移动图纸接着选择\n",
      "第0组图片识别结果：\n",
      "--------------------------------------\n",
      "ocr.ipynb\n",
      "第1组图片识别结果：\n",
      "--------------------------------------\n",
      "河南省住房和\n",
      "成建设斤\n",
      "------------------------------------------------\n",
      "总共输出的字符串数量有3条\n",
      "------------------------------------------------\n",
      "end\n"
     ]
    }
   ],
   "source": [
    "# -*- coding: utf-8 -*-\n",
    "\"\"\"\n",
    "Created on Sun Mar 13 08:36:05 2022\n",
    "\n",
    "@author: Administrator\n",
    "\"\"\"\n",
    "from PIL import Image, ImageGrab\n",
    "import cv2\n",
    "import win32gui,win32api,win32con\n",
    "from win32api import GetSystemMetrics as gsm\n",
    "import time\n",
    "import matplotlib.pyplot as plt\n",
    "import screeninfo\n",
    "import base64\n",
    "import requests\n",
    "import pyautogui as pg\n",
    "#import PyHook3 as pk\n",
    "#import pythoncom\n",
    " \n",
    " \n",
    "def onmouse(event, x, y, flags, param):  # 创建回调函数\n",
    "    global ix, iy, drawing, mode,img_i,img\n",
    "    \n",
    "    if event == cv2.EVENT_LBUTTONDOWN:  # 按下左键\n",
    "        drawing = True  # 开始绘制\n",
    "        ix, iy = x, y  # 赋予按下时的鼠标坐标\n",
    "      \n",
    "    elif event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:  # 当按下左键拖拽鼠标时\n",
    "        if drawing is True:\n",
    "            img2 = img.copy()\n",
    "            cv2.imshow('kw', img)\n",
    "            cv2.rectangle(img2, (ix, iy), (x, y), (0, 255, 0),1)# 当模式为True时画矩形\n",
    "            cv2.imshow('kw', img2)\n",
    "    elif event == cv2.EVENT_LBUTTONUP:  # 当鼠标松开停止绘画\n",
    "        drawing is False\n",
    "        pn1 = ImageGrab.grab((ix+10,iy-5, x+18,y))       \n",
    "        pn1.save(\"fe{0}.png\".format(img_i))\n",
    "        imgg =cv2.imread(\"fe{0}.png\".format(img_i))\n",
    "        \n",
    "        #让图片变暗\n",
    "        img_1 = np.array(imgg)\n",
    "        img_1 = (img_1 * 0.6).astype(\"uint8\")\n",
    "        cv2.imshow('kw{0}'.format(img_i), img_1)\n",
    "        \n",
    "       #  获取句柄，然后置顶\n",
    "        hwnd = win32gui.FindWindow(None, 'kw{0}'.format(img_i))\n",
    "        #消除边框和菜单栏\n",
    "\n",
    "        win32gui.SetWindowLong(hwnd,win32con.GWL_STYLE,win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE) or win32con.WS_EX_LAYERED )\n",
    "        CVRECT=cv2.getWindowImageRect('kw{0}'.format(img_i))\n",
    "    \n",
    "        #顶置\n",
    "        win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST,ix+10,iy-5,CVRECT[2],CVRECT[3], win32con.SWP_SHOWWINDOW)        \n",
    "        #需要重新显示一下否则是黑的，应为上面给了一个显示窗口的类型，下面的语句可以省掉\n",
    "#         win32gui.ShowWindow(hwnd,win32con.SW_SHOW)        \n",
    "        img_i+=1\n",
    "        #下面是文字识别模块\n",
    "    elif event==cv2.EVENT_RBUTTONUP:\n",
    "        pg.press('esc')\n",
    "        \n",
    "class CodeDemo:\n",
    "    def __init__(self,AK,SK,code_url,img_path):\n",
    "        self.AK=AK\n",
    "        self.SK=SK\n",
    "        self.code_url=code_url\n",
    "        self.img_path=img_path\n",
    "        self.access_token=self.get_access_token()\n",
    "\n",
    "    def get_access_token(self):\n",
    "        token_host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={ak}&client_secret={sk}'.format(ak=self.AK,sk=self.SK)\n",
    "        header={'Content-Type': 'application/json; charset=UTF-8'}\n",
    "        response=requests.post(url=token_host,headers=header)\n",
    "        content = response.json()\n",
    "        access_token=content.get(\"access_token\")\n",
    "        return access_token\n",
    "\n",
    "    def getCode(self):\n",
    "        header = {\n",
    "            \"Content-Type\": \"application/x-www-form-urlencoded\"\n",
    "        }\n",
    "        def read_img():\n",
    "            with open(self.img_path, \"rb\")as f:\n",
    "                return base64.b64encode(f.read()).decode()\n",
    "\n",
    "        image = read_img()\n",
    "        response=requests.post(url=self.code_url,data={\"image\":image,\"access_token\":self.access_token},headers=header)\n",
    "        return response.json()\n",
    "  \n",
    "    #对2c25/4c20这样的字符串进行分析计算配筋值，函数为ev(str),返回值为\n",
    "def evdata(str1):\n",
    "    str2=str1.split(\"c\")\n",
    "    str3=str2[0]+\"*\"+\"3.14*((\"+str2[1]+\"/2)**2)\"\n",
    "    return eval(str3)\n",
    "def ev(str):\n",
    "    steel=0\n",
    "    if(\"/\" in str):\n",
    "        strs=str.split(\"/\")\n",
    "        for st in strs: \n",
    "            if(\"+\" in st):\n",
    "                stt=st.split(\"+\")\n",
    "                for tt in stt:\n",
    "                    steel=evdata(tt)+steel    \n",
    "            steel=evdata(st)+steel\n",
    "    elif(\"+\" in str):\n",
    "        stt=str.split(\"+\")\n",
    "        for tt in stt:\n",
    "            steel=evdata(tt)+steel    \n",
    "    else:\n",
    "        steel=evdata(str)\n",
    "    return int(steel)\n",
    "\n",
    "    #截屏框选多个部分进行文字识别，如果只选两个图片判断图片文字是否是原位标注的两个钢筋值，如果是就就输出梁底钢筋\n",
    "    #与梁顶钢筋的比值，如果不是就输出一个所有图片汇总的总字符串列表。\n",
    "def buffcap():\n",
    "    print(\"使用`开始可以进行，鼠标左键截选要识别的文字部分，按m重新选择，按ESC结束选择,再次按ESC退出此模块，鼠标右键也可\")\n",
    "    global ix, iy, drawing, mode,img_i,img,img2,width,height\n",
    "    \n",
    "    screen = screeninfo.get_monitors()[0] \n",
    "    width, height = screen.width, screen.height \n",
    "    pn = ImageGrab.grab((0, 0, 10, 10))\n",
    "    pn.save(\"fx.png\")\n",
    "    img = cv2.imread(\"fx.png\")\n",
    "    cv2.imshow(\"kwx\",img)\n",
    "    cv2.moveWindow(\"kwx\",  width, height)\n",
    "    #给鼠标监控程序赋初值\n",
    "    img_i=0 #选窗计数\n",
    "    drawing = False  # 当鼠标按下变为True\n",
    "    mode = True  # 按下‘m’变成False，true为绘制矩形，false为消除窗口重新选择\n",
    "    ix, iy = -1, -1  # 初始化鼠标位置\n",
    "    \n",
    "    #最开始设置键盘钩子\n",
    "    #keycapture() #不执行这个钩子需要先点击一下下面的窗口\n",
    "\n",
    "\n",
    "    #下面的循环是为了反复选择对话框\n",
    "    while(1):\n",
    "        #print(\"进入截图循环\")\n",
    "        k = cv2.waitKey(1) & 0xFF\n",
    "        if k == 9: #tab键是9\n",
    "            print(\"请使用鼠标左键开始选择，可以多次选择。按“c”后可以移动图纸接着选择\")\n",
    "            pn = ImageGrab.grab((0, 0, width, height))\n",
    "            pn.save(\"fe.png\")\n",
    "            img = cv2.imread(\"fe.png\")\n",
    "            img2 = img.copy()\n",
    "            cv2.imshow(\"kw\",img)\n",
    "            #将全屏截图全屏显示\n",
    "            window_name=\"kw\"\n",
    "            cv2.namedWindow(window_name, cv2.WND_PROP_FULLSCREEN)\n",
    "            cv2.moveWindow(window_name,  -15,  -60)\n",
    "            cv2.setWindowProperty(window_name, cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)\n",
    "            cv2.setMouseCallback(window_name, onmouse)  # 将回调函数与窗口绑定\n",
    "            \n",
    "        elif k == ord('m'):  # 按重新选择\n",
    "            mode = not mode\n",
    "            for i in range(img_i):\n",
    "                cv2.destroyWindow(\"kw{0}\".format(i))\n",
    "            img_i=0\n",
    "            cv2.imshow(\"kw\",img)\n",
    "            \n",
    "        elif k == ord(\"c\"):  # 按ESC退出\n",
    "            print(\"可以重新按tab选择图片，此时设置钩子\")\n",
    "            cv2.destroyWindow(\"kw\")\n",
    "            \n",
    "            ix_old,iy_old,ix_max=0,0,0\n",
    "            for i in range(img_i):\n",
    "                CVRECT=cv2.getWindowImageRect('kw{0}'.format(i))\n",
    "                CVRECT2=cv2.getWindowImageRect('kw{0}'.format(i+1)) if i<img_i-2 else CVRECT\n",
    "                #print(ix_old,iy_old)\n",
    "                if(CVRECT[2]>ix_max):\n",
    "                    ix_max=CVRECT[2]\n",
    "                cv2.moveWindow(\"kw{0}\".format(i),width+ix_old,iy_old)\n",
    "                if iy_old+CVRECT[3]+60+CVRECT2[3]>height:\n",
    "                    ix_old=ix_old+CVRECT[2]\n",
    "                    iy_old=0\n",
    "                else:\n",
    "                    iy_old=iy_old+CVRECT[3]+60\n",
    "                    ix_max=0\n",
    "            #keycapture()   #开始设置钩子等待选择  #不执行这个钩子需要先点击一下下面的窗口\n",
    "\n",
    "                    \n",
    "        elif k == 27:  # 按ESC退出\n",
    "            cv2.destroyAllWindows()\n",
    "            break\n",
    "\n",
    "    \n",
    "    return img_i\n",
    "\n",
    "#键盘钩子，钩住后的执行函数，卸载钩子激活窗口    \n",
    "def keyevent(event):\n",
    "    global hm,width,height,mode,img_i\n",
    "    if event.Key == \"Tab\":\n",
    "        print(\"Tab键发出\")\n",
    "        hm.UnhookKeyboard() #取消键盘钩子\n",
    "        win32api.PostQuitMessage()\n",
    "        label=\"kwx\"\n",
    "        hwnd=win32gui.FindWindow(None, label)\n",
    "        pg.press('Tab')\n",
    "        win32gui.SetForegroundWindow(hwnd)\n",
    "        win32gui.SetActiveWindow(hwnd)\n",
    "        pg.press('Tab')\n",
    "    elif event.Key == \"Escape\":\n",
    "        print(\"Esc键发出\")\n",
    "        hm.UnhookKeyboard() #取消键盘钩子\n",
    "        win32api.PostQuitMessage()\n",
    "        label=\"kwx\"\n",
    "        hwnd=win32gui.FindWindow(None, label)\n",
    "        pg.press('Esc')\n",
    "        win32gui.SetForegroundWindow(hwnd)\n",
    "        win32gui.SetActiveWindow(hwnd)\n",
    "        pg.press('Esc')\n",
    "    return False\n",
    "\n",
    "\n",
    "#设置键盘钩子函数\n",
    "def keycapture():\n",
    "  global  hm  \n",
    "  hm = pk.HookManager()\n",
    "  hm.KeyDown=keyevent\n",
    "  # 设置鼠标键盘“钩子”\n",
    "  hm.HookKeyboard()\n",
    "  print(\"hook start\")\n",
    "  pythoncom.PumpMessages()\n",
    "  return True\n",
    "    \n",
    "    \n",
    "def buffocr():    \n",
    "    #文字识别模块\n",
    "    AK = \"G3EMzSZdAgRp6AZyFVOEnxHV\" # 官网获取的AK\n",
    "    SK = \"l71iVZXpe38r3FqTOlv8KZPYVheInQPO\" # 官网获取的SK\n",
    "    code_url = \"https://aip.baidubce.com/rest/2.0/ocr/v1/accurate\" # 百度图片识别接口地址\n",
    "    steel=[]\n",
    "    strs=[]\n",
    "    for j in range(img_i):    \n",
    "        img_path=r\"fe{0}.png\".format(j) # 识别图片的地址\n",
    "        code_obj=CodeDemo(AK=AK,SK=SK,code_url=code_url,img_path=img_path)#识别语句\n",
    "        res=code_obj.getCode()#获取识别内容\n",
    "        #多个文字识别，速度有可能比较忙，后面的容易出错，加一个判断\n",
    "        print(\"第{0}组图片识别结果：\".format(j))\n",
    "        print(\"--------------------------------------\")\n",
    "        #下面这段代码从道理上比较好，但是运行过程效果不是跳过就是死循环在里面获得不了正确的结果\n",
    "        #应该从获取网络返回值下手，肯定对用有状态码，状态码成功就成功，不成功就等待，等待秒数超时，显示网络超时跳出，提示查看网络连接。\n",
    "        while (True):\n",
    "            time.sleep(0.1)\n",
    "            try:\n",
    "                len_res=len(res.get(\"words_result\"))\n",
    "                #print(\"第{0}张图片识别了{1}条字符串\".format(j,len_res))\n",
    "                break\n",
    "            except TypeError:\n",
    "                print(\"没获取回来,在等0.1秒\")\n",
    "                    \n",
    "                \n",
    "              \n",
    "        #time.sleep(0.5) \n",
    "        len_res=len(res.get(\"words_result\"))\n",
    "        #下面模块显示识别的内容，如果有需求res内还包括文字的位置及大小\n",
    "        str=[]\n",
    "        for i in range(len_res):\n",
    "            code=res.get(\"words_result\")[i].get(\"words\")\n",
    "            code=code.replace(\"业\",\"c\")\n",
    "            code=code.replace(\"亚\",\"c\")\n",
    "            code=code.replace(\"世\",\"c\")\n",
    "            print(code)\n",
    "            #整个截取图片形成一个字符串组\n",
    "            str.append(code)\n",
    "            #判断是否是两个图片，两个图片截取的是否是钢筋，\n",
    "            if((\"c\" in code) and code[0].isdigit() and \";\" not in code and \"；\" not in code and img_i==2): \n",
    "                try:\n",
    "                    print(ev(code))\n",
    "                    steel.append(ev(code))\n",
    "                except :\n",
    "                    print(\"未识别钢筋值或者其他错误\")\n",
    "    #把识别的图片数据加入一个大的字符串组\n",
    "        strs=strs+str\n",
    "        \n",
    "    #如果只有两个钢筋值显示钢筋比值，第一个图片为顶筋，第二个为底筋\n",
    "    if(len(steel)==2):  \n",
    "        try:\n",
    "            print(\"底筋等于{0}，顶筋等于{1}，底筋除顶筋比值为：\".format(steel[1],steel[0]))\n",
    "            print(steel[1]/steel[0])\n",
    "        except :\n",
    "            steel=[]\n",
    "            print(\"出现错误\")\n",
    "    print(\"------------------------------------------------\")\n",
    "    print(\"总共输出的字符串数量有{0}条\".format(len(strs)))\n",
    "    print(\"------------------------------------------------\")\n",
    "    \n",
    "    return strs,steel\n",
    "    \n",
    "    \n",
    "\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    #程序开始   先全屏截图   \n",
    "    print(\"start\")\n",
    "    buffcap()\n",
    "    strs=buffocr()[0]\n",
    "    print(\"end\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(strs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.9"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
